package klochkov.snake.model;

import java.awt.Point;
import java.util.Random;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import klochkov.snake.common.*;

/**
 * The main class of the Snake application's model.
 * 
 * @author Dmitry_Klochkov
 * 
 */
public class Game {
	private FieldCell gameField[][];
	private Snake snake;
	private Frog[] frogs;
	private int score = 0;
	private volatile  GameState state;
	private ExecutorService executor;

	public Game(int fieldSizeX, int fieldSizeY, int numFrogs, int snakeLength) {
		this.gameField = new FieldCell[fieldSizeY][fieldSizeX];
		initializeGameField();
		this.snake = new Snake(this, snakeLength);
		this.executor = Executors.newFixedThreadPool(numFrogs + 1);
		this.frogs = new Frog[numFrogs];
		for (int i = 0; i < frogs.length; i++) {
			frogs[i] = new Frog(this);
		}
		allocateSnake();
		allocateFrogs();
	}

	private void initializeGameField() {
		for (int i = 0; i < gameField.length; i++) {
			for (int j = 0; j < gameField[0].length; j++) {
				gameField[i][j] = new FieldCell();
			}
		}
	}

	private void allocateSnake() {
		int i = snake.getCells().size();
		for (EntityCell c : snake.getCells()) {
			i--;
			c.setY(0);
			c.setX(i);
			gameField[0][i].setEntityCell(c);
		}
	}
	
	/**
	 * Allocate all the frogs on the game field
	 */
	private void allocateFrogs() {
		int randomX;
		int randomY;
		Random random = new Random();
		for (int i = 0; i < frogs.length; i++) {
			while (true) {
				randomX = random.nextInt(gameField[0].length);
				randomY = random.nextInt(gameField.length);
				if (gameField[randomY][randomX].isEmpty()) {
					gameField[randomY][randomX].setEntityCell(frogs[i]
							.getCell());
					frogs[i].getCell().setX(randomX);
					frogs[i].getCell().setY(randomY);
					break;
				}
			}
		}
	}

	public FieldCell[][] getGameField() {
		return gameField;
	}

	/**
	 * Return true if specified point is in the game field
	 */
	public boolean isField(int x, int y) {
		int fieldSizeX = gameField[0].length;
		int fieldSizeY = gameField.length;
		return (x >= 0 && y >= 0) && (x < fieldSizeX && y < fieldSizeY);
	}
	
	/**
	 * Return true if specified field's cell is empty 
	 */
	public boolean isEmpty(int x, int y){
		if(isField(x, y)){
			return gameField[y][x].isEmpty();
		}
		return false;
	}
	
	public Point calcNextCell(int curX, int curY, Direction direction){
		Point p = new Point(curX,curY);
		switch (direction) {
		case UP:
			p.y-=1;
			break;
		case RIGTH:
			p.x+=1;
			break;
		case DOWN:
			p.y+=1;
			break;
		case LEFT:
			p.x-=1;
			break;
		default:
			break;
		}
		return p;
		
	}
	
	public boolean tryLock(int x, int y){
		if(isField(x, y)){
			return gameField[y][x].tryLock();
		}
		return false;
	}
	
	public void unlock(int x, int y){
		gameField[y][x].unlock();
	}
	
	/**
	 * Start the game
	 */
	public void start() {
		state = GameState.STARTED;
		/* revive all the frogs */
		for (Frog f : frogs) {
			executor.execute(f);
		}
		executor.execute(snake);
		/* revive the snake */
		//executor.execute(snake);
		// notify the observers
	}
	
	public Snake getSnake() {
		return snake;
	}
	
	public CellType getCellType(int x, int y){
		if(gameField[y][x].getEntityCell()!=null){
			gameField[y][x].getEntityCell().getCellType();
		}
		return CellType.EMPTY;
	}

	public void pause(){
		
	}
	
	public void stop(){
		state = GameState.GAME_OVER;
	}

	
	public GameState getState() {
		return state;
	}

	
}
